﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Data.GameData.Entities;
using Data.GameData.GameMap;
using Data.GameData.Utils;

namespace Data.GameData
{
    public class StarSystem : GameObject
    {
        #region Attributes
        private EStarSystem dbStarSystem;
        private static Dictionary<Guid, StarSystem> starSystemList = null;

        private int mapId;
        private StarSystemType type;
        private StarSystemEnviroment enviroment;

        // System bodies
        private List<SystemBody> suns = new List<SystemBody>();
        private List<SystemBody> bodies = new List<SystemBody>();
        // System Warp Points

        #endregion

        #region Constructors
        public StarSystem()
        {
            dbStarSystem = new EStarSystem();
            mapId = Map.CreateMap();
            MarkNew();
        }
        
        public StarSystem(Guid id)
        {
            dbStarSystem = new EStarSystem();

            if (id != Guid.Empty)
            {
                dbStarSystem = EStarSystem.LoadFromDB(id);
                Load();
            }
        }

        private StarSystem(EStarSystem entity)
        {
            this.dbStarSystem = entity;
            Load();
        }
        #endregion

        #region Public Static Properties
        static public List<StarSystem> StarSystems
        {
            get
            {
                if (starSystemList == null || starSystemList.Count() == 0) FetchStarSystems();
                return new List<StarSystem>(starSystemList.Values);
            }
        }

        static public StarSystem GetStarSystem(Guid id)
        {
            if (starSystemList == null || starSystemList.Count() == 0) FetchStarSystems();
            return starSystemList.Values.FirstOrDefault(sSys => sSys.Id == id);
        }

        static public StarSystem[] GetStarSystems()
        {
            return StarSystems.ToArray();
        }
        #endregion

        #region Public Properties
        public int MapId
        {
            get { return mapId; }
            set { }
        }

        public StarSystemType Type
        {
            get { return type; }
            set
            {
                if (type == value) return;
                type = value;
                MarkDirty();
            }
        }

        public StarSystemEnviroment Enviroment
        {
            get { return enviroment; }
            set
            {
                if (enviroment == value) return; 
                enviroment = value;
                MarkDirty();
            }
        }

        public IEnumerable<SystemBody> Suns
        {
            get
            {
                if (suns.Count == 0) suns.AddRange(SystemBody.AllBodiesInSystem(Id, SystemBodyType.SUN));
                return suns;
            }
            set { }
        }

        public IEnumerable<SystemBody> Bodies
        {
            get
            {
                if (bodies.Count == 0) bodies.AddRange(SystemBody.AllBodiesInSystem(Id, SystemBodyType.PLANET));
                return bodies; 
            }
            set { }
        }
        #endregion

        #region Static Private Methods
        static private void FetchStarSystems()
        {
            if (starSystemList == null || starSystemList.Count == 0)
            {
                starSystemList = new Dictionary<Guid, StarSystem>();

                List<EStarSystem> entityList = EStarSystem.GetAllForGame(Game.ActiveGame.Id);
                lock (starSystemList)
                {
                    //
                    foreach (EStarSystem entity in entityList)
                    {
                        StarSystem obj = new StarSystem(entity);
                        starSystemList.Add(obj.Id, obj);
                    }
                }
            }
        }

        #endregion

        #region Public Static Methods
        public static void Add(StarSystem sys)
        {
            if (starSystemList == null || starSystemList.Count == 0) FetchStarSystems();
            if (!starSystemList.ContainsKey(sys.Id))
                starSystemList.Add(sys.Id, sys);
        }

        public static void Remove(StarSystem sys)
        {
            if (starSystemList == null || starSystemList.Count == 0) FetchStarSystems();
            starSystemList.Remove(sys.Id);
        }
        #endregion

        #region Public Methods
        public void AddSun(SystemBody sun)
        {
            if (!suns.Contains(sun))
            {
                suns.Add(sun);
                MarkDirty();
            }
        }

        public void AddBody(SystemBody body)
        {
            if (!bodies.Contains(body))
            {
                bodies.Add(body);
                MarkDirty();
            }
        }

        public void ClearBodies()
        {
            if (bodies.Count() == 0) return;
            bodies.Clear();
            MarkDirty();
        }
        #endregion

        #region BaseObject overrides - Save, Update, etc
        public override void Save()
        {
            // Save links this is dependent on

            // Save this
            base.Save();

            // Save link dependent on this
            foreach (SystemBody sun in Suns)
                sun.Save();
            foreach (SystemBody body in Bodies)
                body.Save();
        }

        public static void SaveAll()
        {
            if (starSystemList == null)
                return;

            foreach (StarSystem star in starSystemList.Values)
                star.Save();
        }

        internal override void Update()
        {
            if (MarkedToDelete)
            {
                // Delete dependencies

                DeleteNow();
            }
            else //if(IsNew || IsDirty)
            {
                if (IsNew)
                {
                    if (starSystemList == null) starSystemList = new Dictionary<Guid, StarSystem>();
                    //starSystemList.Add(this.Id, this);
                }

                SaveValues();
                dbStarSystem.SaveToDB(IsNew);
            }
        }

        internal override void DeleteNow()
        {
            if (dbStarSystem.Values == null)
                dbStarSystem.Values = new Stitch.Database.DBRow();

            dbStarSystem.Values["id"] = Id;

            dbStarSystem.Delete();

            //
            starSystemList.Remove(Id);
            MarkDeleted();
        }

        internal override void SaveValues()
        {
            if (dbStarSystem.Values == null)
                dbStarSystem.Values = new Stitch.Database.DBRow();

            dbStarSystem.Values["id"] = Id;
            dbStarSystem.Values["gameId"] = Game.ActiveGame.Id;
            dbStarSystem.Values["mapId"] = MapId;
            dbStarSystem.Values["type"] = EnumUtils.StringValueOf(Type);
            dbStarSystem.Values["enviroment"] = EnumUtils.StringValueOf(Enviroment);
        }

        internal override void LoadValues()
        {
            if (dbStarSystem.Values == null)
                return;

            Id = dbStarSystem.Values["id"];
            MapId = dbStarSystem.Values["mapId"];
            Type = (StarSystemType)EnumUtils.EnumValueOf(dbStarSystem.Values["type"], typeof(StarSystemType));
            Enviroment = (StarSystemEnviroment)EnumUtils.EnumValueOf(dbStarSystem.Values["enviroment"], typeof(StarSystemEnviroment));
        }

        internal override void InitialiseObject()
        {
            SystemBody.GetSystemBodies();
        }
        #endregion
    }
}
